Add codec to encode/decode GRPC data frame.#414
Add codec to encode/decode GRPC data frame.#414mattklein123 merged 16 commits intoenvoyproxy:masterfrom fengli79:master
Conversation
|
Is there any reason why this is written from scratch and not using https://github.com/grpc/grpc? |
|
Per @PiotrSikora it would be very, very, very nice if we could work with the gRPC c++ folks to refactor slightly so that we can consume the generated RPC stubs (codec, etc.) but provide our own transport. I already replicated some stuff for unary calls out of expediency, but now that you are all involved it would be great to fix this for real. Can we at least SWAG what it would take before reimplementing? |
|
@ctiller - Hey Craig! Its probably a good time to start discussing some of the integration points between Envoy and GRPC In this particular instance WDYT? Would it be easy to factor out the framing code from core? If not then this should probably proceed as is and we have a longer term goal around factoring |
|
Any chance to get this submitted? Refactor GRPC c core to reuse the framer is not trivial and won't happen any time soon. Here's the situation:
|
|
@fengli79 I wasn't aware this was ready for review. @RomanDzhabarov can you take a first pass? |
|
will check this tonight |
source/common/grpc/codec.h
Outdated
| // @param input supplies the binary octets wrapped in a GRPC data frame. | ||
| // @param input supplies the buffer to store the decoded data. | ||
| // @return bool whether the decoding success. | ||
| bool Decode(Buffer::Instance& input, std::vector<Frame>* output); |
There was a problem hiding this comment.
usually in envoy we pass by ref in this case (less to deal with null checks, alloc/dealloc/etc).
source/common/grpc/codec.h
Outdated
|
|
||
| // Decodes the given buffer with GRPC data frame. | ||
| // @param input supplies the binary octets wrapped in a GRPC data frame. | ||
| // @param input supplies the buffer to store the decoded data. |
source/common/grpc/codec.h
Outdated
| // @param flags supplies the GRPC data frame flags. | ||
| // @param length supplies the GRPC data frame length. | ||
| // @param output the buffer to store the encoded data, it's size must be 5. | ||
| void NewFrame(uint8_t flags, uint64_t length, uint8_t* output); |
There was a problem hiding this comment.
using std::array<uint8_t, 5>? (would be good to enforce size 5 requirement here)
source/common/grpc/codec.h
Outdated
| bool Decode(Buffer::Instance& input, std::vector<Frame>* output); | ||
|
|
||
| private: | ||
| // Wiring format of GRPC data frame header: |
There was a problem hiding this comment.
can you also put a link to official docs if any for this format?
source/common/grpc/codec.h
Outdated
| // @param flags supplies the GRPC data frame flags. | ||
| // @param length supplies the GRPC data frame length. | ||
| // @param output the buffer to store the encoded data, it's size must be 5. | ||
| void NewFrame(uint8_t flags, uint64_t length, uint8_t* output); |
source/common/grpc/codec.h
Outdated
| // @param input supplies the binary octets wrapped in a GRPC data frame. | ||
| // @param input supplies the buffer to store the decoded data. | ||
| // @return bool whether the decoding success. | ||
| bool Decode(Buffer::Instance& input, std::vector<Frame>* output); |
source/common/grpc/codec.h
Outdated
| struct Frame { | ||
| uint8_t flags; | ||
| uint32_t length; | ||
| Buffer::Instance* data; |
Change to use Buffer::IntancePtr.
mattklein123
left a comment
There was a problem hiding this comment.
a few nits otherwise looks good
source/common/grpc/codec.h
Outdated
| @@ -0,0 +1,78 @@ | |||
| #pragma once | |||
|
|
|||
| #include <array> | |||
There was a problem hiding this comment.
del or add to precompiled header
source/common/grpc/codec.h
Outdated
| enum class CompressionAlgorithm { None, Gzip }; | ||
|
|
||
| struct Frame { | ||
| uint8_t flags; |
There was a problem hiding this comment.
_ postfix for members (.e.g, flags_)
There was a problem hiding this comment.
Is it needed for public struct?
There was a problem hiding this comment.
We have been doing this for public structs so to be consistent I would change it. (I don't really care that much about this but might as well be consistent).
source/common/grpc/codec.h
Outdated
| // Creates a new GRPC data frame with the given flags and length. | ||
| // @param flags supplies the GRPC data frame flags. | ||
| // @param length supplies the GRPC data frame length. | ||
| // @param output the buffer to store the encoded data, it's size must be 5. |
There was a problem hiding this comment.
"... data. Its size must be 5."
source/common/grpc/codec.h
Outdated
| // Decodes the given buffer with GRPC data frame. | ||
| // @param input supplies the binary octets wrapped in a GRPC data frame. | ||
| // @param output supplies the buffer to store the decoded data. | ||
| // @return bool whether the decoding success. |
source/common/grpc/codec.h
Outdated
| bool decode(Buffer::Instance& input, std::vector<Frame>& output); | ||
|
|
||
| private: | ||
| // Wiring format (http://www.grpc.io/docs/guides/wire.html) of GRPC data frame |
source/common/grpc/codec.h
Outdated
| // | ||
| // A fixed header consists of five bytes. | ||
| // The first byte is the Flag. The last one "C" bit indicates if the message | ||
| // is compressed or not (0 is uncompressed, 1 is compressed). The rest seven |
source/common/grpc/codec.h
Outdated
| // A fixed header consists of five bytes. | ||
| // The first byte is the Flag. The last one "C" bit indicates if the message | ||
| // is compressed or not (0 is uncompressed, 1 is compressed). The rest seven | ||
| // "R" bits is reserved for future use. |
test/common/grpc/codec_test.cc
Outdated
| @@ -0,0 +1,115 @@ | |||
| #include <array> | |||
There was a problem hiding this comment.
del or add to precompiled header
|
|
||
| #include "common/buffer/buffer_impl.h" | ||
| #include "common/grpc/codec.h" | ||
| #include "test/generated/helloworld.pb.h" |
There was a problem hiding this comment.
nit: newline before this line
| EXPECT_EQ("hello", result.name()); | ||
| } | ||
| } | ||
| } // Grpc |
There was a problem hiding this comment.
nit: newline before this line
source/common/grpc/codec.cc
Outdated
| output.push_back(std::move(frame_)); | ||
| frame_.flags = 0; | ||
| frame_.length = 0; | ||
| frame_.data.reset(); |
There was a problem hiding this comment.
do not think there is a need to .reset() here as ownership was transferred to the frame in output
test/common/grpc/codec_test.cc
Outdated
|
|
||
| std::vector<Frame> frames; | ||
| Decoder decoder; | ||
| decoder.decode(buffer, frames); |
There was a problem hiding this comment.
EXPECT_TRUE and in the case below
|
LGTM, one comment left |
| } | ||
| } | ||
| } | ||
| return true; |
There was a problem hiding this comment.
We might want to check state_ to see if the input was a partial GRPC frame? (e.g. frame length = 100 but only 10 bytes in input buffer.
Also add a test for that case.
There was a problem hiding this comment.
Test added.
You don't need to check the state_. If grpc call get aborted when decoding, you should be able to know that from the HTTP2 layer, as the stream will be reset. Any intermediate state and buffer can be discarded. The workflow would be keep feeding data to the decoder as they arrive and check if there's one or more complete frame get decoded.
|
@fengli79 one other thing came to mind when I read @lizan comment. You aren't draining the buffer anywhere. I'm not sure if this is intentional, but either way I think some changes are needed:
|
|
It's not intended, the caller need to drain the data when needed, as the
test did.
…On Thu, Feb 9, 2017 at 7:58 AM Matt Klein ***@***.***> wrote:
@fengli79 <https://github.com/fengli79> one other thing came to mind when
I read @lizan <https://github.com/lizan> comment. You aren't draining the
buffer anywhere. I'm not sure if this is intentional, but either way I
think some changes are needed:
1. If you intend for the caller to drain the buffer, you should change
decode() to take a const Buffer::Instance&, and document that decode
consumes all bytes if it returns true. Then the caller can drain.
2. Have decode() drain the buffer itself, and document that it will
drain all data, and add tests to this effect.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#414 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AT1vm4lDTp4F8x10Sp3-DqHw_2g1crNvks5raze2gaJpZM4L1tyn>
.
|
|
The decoder takes all the data, no matter it returns true or false. It can
be written in a way to drain the data always to make it work like a move.
However let the caller drain data as needed is more flexible. The envoy
buffer is a wrapper which is not very convenient for decoding, to get best
performance, I would prefer to get a buffer can be modified in flight, like
remove/modify byte in a slice and add/remove slice in the buffer.
…On Thu, Feb 9, 2017 at 8:13 AM Feng Li ***@***.***> wrote:
It's not intended, the caller need to drain the data when needed, as the
test did.
On Thu, Feb 9, 2017 at 7:58 AM Matt Klein ***@***.***>
wrote:
@fengli79 <https://github.com/fengli79> one other thing came to mind when
I read @lizan <https://github.com/lizan> comment. You aren't draining the
buffer anywhere. I'm not sure if this is intentional, but either way I
think some changes are needed:
1. If you intend for the caller to drain the buffer, you should change
decode() to take a const Buffer::Instance&, and document that decode
consumes all bytes if it returns true. Then the caller can drain.
2. Have decode() drain the buffer itself, and document that it will
drain all data, and add tests to this effect.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#414 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AT1vm4lDTp4F8x10Sp3-DqHw_2g1crNvks5raze2gaJpZM4L1tyn>
.
|
|
OK that's fine. Then just make the param const and document that all bytes are consumed if it's not already documented. |
Change the CodecTest to GrpcCodecTest.
|
@mattklein123 With a second think, I change it to drain the inputs when decoding succeeded. Also change the CodecTest to GrpcCodecTest to avoid naming conflicts with other tests. |
|
@fengli79 looks good. I forgot that you need to sign CLA. Can you ACK back when done and I will merge. |
|
Signed.
…On Thu, Feb 9, 2017 at 10:09 AM Matt Klein ***@***.***> wrote:
@fengli79 <https://github.com/fengli79> looks good. I forgot that you
need to sign CLA. Can you ACK back when done and I will merge.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#414 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AT1vm9uUoeSe4xkW9wGMfnr1W945PgGQks5ra1ZagaJpZM4L1tyn>
.
|
* Revert "envoy sha update (envoyproxy#414)" This reverts commit ebb5ef1. * Revert "Fix mixer forward attribute bug. (envoyproxy#412)" This reverts commit 4f07917.
Automatic merge from submit-queue. [DO NOT MERGE] Auto PR to update dependencies of mixerclient This PR will be merged automatically once checks are successful. ```release-note none ```
….rst (envoyproxy#414) * zh-translation:docs/root/configuration/observability/access_log/usage.rst * zh-translation:docs/root/configuration/observability/access_log/usage.rst * zh-translation:docs/root/configuration/observability/access_log/usage.rst * zh-translation:docs/root/configuration/observability/access_log/usage.rst Co-authored-by: 包仁义 <renyi.bao@yiducloud.cn>
**Commit Message** This fixes the latest chart's image tag which previously was set to v0.0.0-latest. This fixes the helm-package recipe and now it points to :latest. **Related Issues/PRs (if applicable)** Follow up on #395 Signed-off-by: Takeshi Yoneda <t.y.mathetake@gmail.com>
Add codec to encode/decode GRPC data frame.